/* $Header: p_gastask.c,v 2.2 01/10/02 10:27:49 przybyls Exp $ */

/***********************************************************************/
/*                                                                     */
/*                  Copyright Hewlett-Packard Co. 1991                 */
/*                                                                     */
/***********************************************************************/

/***********************************************************************/
/* MODULE NAME: gastask.c                                              */
/* ============                                                        */
/*                                                                     */
/* Author:                                                             */
/*                                                                     */
/* MODULE PURPOSE: Background NewtOS task for flow calculations        */
/*                                                                     */
/*                                                                     */
/*                                                                     */
/***********************************************************************/


/*****************************/
/*   GLOBAL INCLUDE FILES    */
/*****************************/

#include  <typedefs.h>
#include <p_wkfile.h>
#include <wkfile.h>
#include <ramps.h>
#include <zone_config.h>
#include <zone_status.h>
#include <list_mgmt.h>
#include <p_status.h>
#include <status.h>
#include  <stddef.h>
#include  <std_ops.h>
#include  <i_op.h>
#include  <task_pub.h>
#include  <error.h>
#include  <display.h>
#include  <pcb_defs.h>
#include  <messages.h>
#include <exception.h>   /* to use SetException */
#include <err_handler.h> /* to use SetException */
#include <glp.h>
#include <keyboard.h>

/*****************************/
/*   LOCAL INCLUDE FILES     */
/*****************************/

#include "proto.h"

/*****************************/
/*   GLOBAL VARIABLES        */
/*****************************/

RESOURCE Task_Cmd_Resource;


/*****************************/
/*   EXTERNAL VARIABLES      */
/*****************************/

  /* forward prototypes for the local executors */

static void DoInletGas       ( U_INT32 parm, void *status, U_INT8 number );
static void DoDetGas         ( U_INT32 parm, void *status, U_INT8 number );
static void DoAuxGas         ( U_INT32 parm, void *status, U_INT8 number );
static void DoInletCalib     ( U_INT32 parm, void *status, U_INT8 number );
static void DoDetCalib       ( U_INT32 parm, void *status, U_INT8 number );
static void DoPneuAuxCalib   ( U_INT32 parm, void *status, U_INT8 number );
static void DoCalcSensorNoise( U_INT32 parm, void *status, U_INT8 number );
static void DoFsAutoZero     ( U_INT32 parm, void *status, U_INT8 number );
static void DoFsUserZero     ( U_INT32 parm, void *status, U_INT8 number );
static void ExecTestCmd      ( U_INT32 parm, void *status, U_INT8 number );
static void SaveInletPids    ( U_INT32 parm, void *status, U_INT8 number );
static void SaveDetPids      ( U_INT32 parm, void *status, U_INT8 number );
static void ReadInletPids    ( U_INT32 parm, void *status, U_INT8 number );
static void ReadDetPids      ( U_INT32 parm, void *status, U_INT8 number );

/*****************************/
/*   LOCAL DEFINES           */
/*****************************/

#define F_INL_AUTO_CAL 1
#define B_INL_AUTO_CAL 2


#define AUTO_CAL_DELAY  Inst_Status.Pneu.Auto_Cal_Delay


#define CALIB               0
#define SCRATCH             1
#define FACTORY_CALIB       2
#define ENABLE_USER         3
#define DISABLE_USER        4



typedef void (*EXECUTOR)( U_INT32 parm, void *status, U_INT8 number );

typedef struct
        {
             U_INT8   cmd_number;
             BIT8     allow_duplicates;
             EXECUTOR executor;
             void     *status_ptr;
             U_INT8   number;

        }GAS_TASK_ENTRY_DEF, *pGAS_TASK_ENTRY_DEF;



static const GAS_TASK_ENTRY_DEF Gas_Task_Cmd_Table[  ] =  {

#define FRNT_INLET_GAS      0
      { FRNT_INLET_GAS,         FALSE,   DoInletGas,       (void *)&Inst_Status.Pneu.Frnt_Inlet,      0  },

#define BACK_INLET_GAS      1
      { BACK_INLET_GAS,         FALSE,   DoInletGas,       (void *)&Inst_Status.Pneu.Back_Inlet,      0  },

#define FDET_FUEL_GAS       2
      { FDET_FUEL_GAS,          FALSE,   DoDetGas,         (void *)&Inst_Status.Pneu.Frnt_Detector,   1  },

#define FDET_UTIL_GAS       3
      { FDET_UTIL_GAS,          FALSE,   DoDetGas,         (void *)&Inst_Status.Pneu.Frnt_Detector,   2  },

#define FDET_MUG_GAS        4
      { FDET_FUEL_GAS,          FALSE,   DoDetGas,         (void *)&Inst_Status.Pneu.Frnt_Detector,   3  },

#define BDET_FUEL_GAS       5
      { BDET_FUEL_GAS,          FALSE,   DoDetGas,         (void *)&Inst_Status.Pneu.Back_Detector,   1  },

#define BDET_UTIL_GAS       6
      { BDET_UTIL_GAS,          FALSE,   DoDetGas,         (void *)&Inst_Status.Pneu.Back_Detector,   2  },

#define BDET_MUG_GAS        7
      { BDET_MUG_GAS,           FALSE,   DoDetGas,         (void *)&Inst_Status.Pneu.Back_Detector,   3  },

#define AUX_3_GAS           8
      { AUX_3_GAS,              FALSE,   DoAuxGas,         (void *)&Inst_Status.Pneu.Aux.Aux_3,       3  },

#define AUX_4_GAS           9
      { AUX_4_GAS,              FALSE,   DoAuxGas,         (void *)&Inst_Status.Pneu.Aux.Aux_4,       4  },

#define AUX_5_GAS          10
      { AUX_5_GAS,              FALSE,   DoAuxGas,         (void *)&Inst_Status.Pneu.Aux.Aux_5,       5  },

#define FRNT_INLET_CALIB   11
      { FRNT_INLET_CALIB,       TRUE,    DoInletCalib,     (void *)&Inst_Status.Pneu.Frnt_Inlet,      0  },

#define BACK_INLET_CALIB   12
      { BACK_INLET_CALIB,       TRUE,    DoInletCalib,     (void *)&Inst_Status.Pneu.Back_Inlet,      0  },

#define FRNT_DET_CALIB     13
      { FRNT_DET_CALIB,         TRUE,    DoDetCalib,       (void *)&Inst_Status.Pneu.Frnt_Detector,   0  },

#define BACK_DET_CALIB     14
      { BACK_DET_CALIB,         TRUE,    DoDetCalib,       (void *)&Inst_Status.Pneu.Back_Detector,   0  },

#define PNEU_AUX_CALIB     15
      { PNEU_AUX_CALIB,         TRUE,    DoPneuAuxCalib,   (void *)&Inst_Status.Pneu.Aux,             0  },

#define CALC_SENSOR_NOISE  16
      { CALC_SENSOR_NOISE,      FALSE,   DoCalcSensorNoise, (void *)0,                                0  },

#define FS_AUTO_ZERO       17
      { FS_AUTO_ZERO,           FALSE,   DoFsAutoZero,     (void *)0,                                 0  },

#define FI_FLOW_ZERO       18
      { FI_FLOW_ZERO,           FALSE,   DoFsUserZero,     (void *)&Inst_Status.Pneu.Frnt_Inlet,      0  },

#define BI_FLOW_ZERO       19
      { BI_FLOW_ZERO,           FALSE,   DoFsUserZero,     (void *)&Inst_Status.Pneu.Back_Inlet,      0  },

#define EXEC_TEST_CMD      20
      { EXEC_TEST_CMD,          FALSE,   ExecTestCmd,      (void *)0,                                 0  },

#define SAVE_FI_PIDS       21
      { SAVE_FI_PIDS,           TRUE,    SaveInletPids,    (void *)&Inst_Status.Pneu.Frnt_Inlet,      0  },

#define SAVE_BI_PIDS       22
      { SAVE_BI_PIDS,           TRUE,    SaveInletPids,    (void *)&Inst_Status.Pneu.Back_Inlet,      0  },

#define SAVE_FD_PIDS       23
      { SAVE_FD_PIDS,           TRUE,    SaveDetPids,      (void *)&Inst_Status.Pneu.Frnt_Detector,   0  },

#define SAVE_BD_PIDS       24
      { SAVE_BD_PIDS,           TRUE,    SaveDetPids,      (void *)&Inst_Status.Pneu.Back_Detector,   0  },

#define READ_FI_PIDS       25
      { READ_FI_PIDS,           TRUE,    ReadInletPids,    (void *)&Inst_Status.Pneu.Frnt_Inlet,      0  },

#define READ_BI_PIDS       26
      { READ_BI_PIDS,           TRUE,    ReadInletPids,    (void *)&Inst_Status.Pneu.Back_Inlet,      0  },

#define READ_FD_PIDS       27
      { READ_FD_PIDS,           TRUE,    ReadDetPids,      (void *)&Inst_Status.Pneu.Frnt_Detector,   0  },

#define READ_BD_PIDS       28
      { READ_BD_PIDS,           TRUE,    ReadDetPids,      (void *)&Inst_Status.Pneu.Back_Detector,   0  },


 };

#define MAX_CMD_NUM  ( sizeof( Gas_Task_Cmd_Table ) / sizeof( GAS_TASK_ENTRY_DEF )  )

U_INT8 Pending_Cmds [ 2 * MAX_CMD_NUM ];


/*****************************/
/*   IMPLEMENT SECTION       */
/*****************************/
/***********************************************************************/
/* FUNCTION:                                                           */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:                                                            */
/*                                                                     */
/* RETURNED VALUE:                                                     */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/***********************************************************************/
/**begin_proto**/

INT16 ReadInletCalFlowOffset ( pINLET_STATUS status )

/**end_proto**/
{

      U_INT16 temp;
      INT16 offset;

      temp = status->Tcomp_Tables->Thermistor.Module_Temperature;

      offset = CalcFlowCalibOffset( status->Flow_Adc_Actual, status, temp );

      return offset;
}

/**begin_proto**/

UI_ERR SaveInletCalFlowOffset ( pINLET_STATUS status, INT16 offset )        /* from manually invoked flow calib */

/**end_proto**/
{

      UI_ERR error;
      pFLOW_SENSOR_STRUCT sensor;
      U_INT16 temp;

      sensor = &status->Tcomp_Tables->Flow_Sensor;
      temp = status->Tcomp_Tables->Thermistor.Module_Temperature;

      if ((error = ValidateFlowOffset( offset, status->IU_Scaling, sensor, temp )) != OK ) return error;

      status->Calib.F_Sensor_Offset = offset;

      if ( !SaveAutoCalOffset ( status, offset ) )                   /* updates auto_flow_offset ONLY   */
      {
          TrashModule( status->Module_Number );
          return OK; /* set exception in Trash Module will indicate the error */
      }

      SaveInletCalib( status );                                      /* update calib_state, ALL user_calib_info, date */

      LogSetptChange( status->Position == FRNT_INLET ? F_INLET_CAL_FLOW_OFFSET : B_INLET_CAL_FLOW_OFFSET, 0, 0 );

      status->Ready.Setpt_Change = TRUE;

      return OK;
}

/**begin_proto**/

UI_ERR AutoSaveInletFlowOffset ( pINLET_STATUS status, INT16 offset )      /* from post-run auto-invoked flow calib */

/**end_proto**/
{

      UI_ERR error;
      pFLOW_SENSOR_STRUCT sensor;
      U_INT16 temp;

      sensor = &status->Tcomp_Tables->Flow_Sensor;
      temp = status->Tcomp_Tables->Thermistor.Module_Temperature;

      if ((error = ValidateFlowOffset( offset, status->IU_Scaling, sensor, temp )) != OK ) return error;

      status->Calib.F_Sensor_Offset = offset;

      if ( !WriteUserPos2Offset   ( status->Module_Number, offset ) ||         /* updates user_flow_offset, state */
           !SaveAutoCalOffset ( status, offset ) )                             /* updates auto_flow_offset        */
      {
           TrashModule ( status->Module_Number );
           return OK; /* set exception in Trash Module will indicate the error */
      }

      LogSetptChange( status->Position == FRNT_INLET ? F_INLET_CAL_FLOW_OFFSET : B_INLET_CAL_FLOW_OFFSET, 0, 0 );

      status->Ready.Setpt_Change = TRUE;
      return OK;
}

/**begin_proto**/

UI_ERR SaveFsCalOffset ( pINLET_STATUS status, INT16 offset, BIT8 auto_cal )

/**end_proto**/
{

     UI_ERR   error;

     error = OK;

     if ( !auto_cal )
     {
         /* manual cal only saves the user value */
         error =  SaveInletCalFlowOffset ( status, offset );
     }
     else
     {
         /* auto cal saves both factory and user calib values */
         error = AutoSaveInletFlowOffset ( status, offset );
     }

     if (error == OK )
     {
         DownloadInletPids( status );
     }
     else
     {
         if ( auto_cal )
         {
             SetException( (status->Position == FRNT_INLET) ? FI_FS_AUTO_CAL_FAILED : BI_FS_AUTO_CAL_FAILED );
         }
     }

     return error;
}


/**begin_proto**/

void RequestFlowSensorAutoZero()

/**end_proto**/
{
   U_INT32 parm_mask;

   /* only called from run-task's post run transition */

   if ( Actual_Equals_Setpt ) return;

   INTERRUPTS_OFF

   parm_mask = 0;

   /* set the bits that force us into not ready to prevent the post_run -> pre_run transition */

   if (( Inst_Config.Pneu.Frnt_Inlet.FS_Auto_Cal ) &&
       ( Active_Wkfile.Pneu.Frnt_Inlet.On_Off == ON ) &&
       (( Inst_Config.Pneu.Frnt_Inlet.Type == SS  )         ||
        ( Inst_Config.Pneu.Frnt_Inlet.Type == PP  )         ||
        ( Inst_Config.Pneu.Frnt_Inlet.Type == ACI )         ||
        ( Inst_Config.Pneu.Frnt_Inlet.Type == SIMDIST)      ||
        ( Inst_Config.Pneu.Frnt_Inlet.Type == PTV )         ||
        ( Inst_Config.Pneu.Frnt_Inlet.Type == CIS4 )        ||
        ( Inst_Config.Pneu.Frnt_Inlet.Type == VOLATILES )   ||
        ( Inst_Config.Pneu.Frnt_Inlet.Type == CIS3      )     )             )
   {
     if (( Inst_Config.Pneu.Frnt_Inlet.Type == SS )                                        &&
         ( Inst_Status.Pneu.Frnt_Inlet.Wkfile->Injection_Mode == SPLITLESS )               &&
         ( Inst_Status.Pneu.Frnt_Inlet.Wkfile->Purge_Time == RetTimeToMilliSecs ( 999990 )))
     {
     /* special operating mode for Restek inlet liner - suppress auto zero */
     }
     else
     {
       Inst_Status.Pneu.Frnt_Inlet.Ready.FS_Auto_Zero = TRUE;
       parm_mask |= F_INL_AUTO_CAL;
       if ( Inst_Status.Pneu.Frnt_Inlet.Ready.Pres.Controlled )
       {
          SetNewException  ( FRNT_INLET_PRESSURE, GetInletPresActual( &Inst_Status.Pneu.Frnt_Inlet ), 0 );
       }

       if ( Inst_Status.Pneu.Frnt_Inlet.Ready.Flow.Controlled )
       {
          SetNewException  ( FRNT_INLET_FLOW, GetInletFlowActual( &Inst_Status.Pneu.Frnt_Inlet ), 0 );
       }
     }
   }

   if (( Inst_Config.Pneu.Back_Inlet.FS_Auto_Cal ) &&
       ( Active_Wkfile.Pneu.Back_Inlet.On_Off == ON ) &&
       (( Inst_Config.Pneu.Back_Inlet.Type == SS  )          ||
        ( Inst_Config.Pneu.Back_Inlet.Type == PP  )          ||
        ( Inst_Config.Pneu.Back_Inlet.Type == ACI )          ||
        ( Inst_Config.Pneu.Back_Inlet.Type == SIMDIST)       ||
        ( Inst_Config.Pneu.Back_Inlet.Type == PTV )          ||
        ( Inst_Config.Pneu.Back_Inlet.Type == CIS4 )         ||
        ( Inst_Config.Pneu.Back_Inlet.Type == VOLATILES  )   ||
        ( Inst_Config.Pneu.Back_Inlet.Type == CIS3  )) )
   {
     if (( Inst_Config.Pneu.Back_Inlet.Type == SS )                                        &&
         ( Inst_Status.Pneu.Back_Inlet.Wkfile->Injection_Mode == SPLITLESS )               &&
         ( Inst_Status.Pneu.Back_Inlet.Wkfile->Purge_Time == RetTimeToMilliSecs ( 999990 )))
     {
     /* special operating mode for Restek inlet liner - suppress auto zero */
     }
     else
     {
       Inst_Status.Pneu.Back_Inlet.Ready.FS_Auto_Zero = TRUE;
       parm_mask |= B_INL_AUTO_CAL;
       if ( Inst_Status.Pneu.Back_Inlet.Ready.Pres.Controlled )
       {
          SetNewException  ( BACK_INLET_PRESSURE, GetInletPresActual( &Inst_Status.Pneu.Back_Inlet ), 0 );
       }

       if ( Inst_Status.Pneu.Back_Inlet.Ready.Flow.Controlled )
       {
          SetNewException  ( BACK_INLET_FLOW, GetInletFlowActual( &Inst_Status.Pneu.Back_Inlet ), 0 );
       }
     }
   }

   if ( parm_mask != 0 ) SendGasTaskCmd( FS_AUTO_ZERO, parm_mask );

   INTERRUPTS_ON
}



/**begin_proto**/

void BkgrndRequestFsZero( pINLET_STATUS status, BIT8 data_comm )

/**end_proto**/
{
   LockResource( &Task_Cmd_Resource );

   SendGasTaskCmd( (status->Position == FRNT_INLET) ? FI_FLOW_ZERO : BI_FLOW_ZERO, data_comm );

   ReleaseResource( & Task_Cmd_Resource );
}


/**begin_proto**/

void AutoZeroFlowSensors( U_INT32 parm )

/**end_proto**/
{

#define do_fi (( parm & F_INL_AUTO_CAL ) != 0 )
#define do_bi (( parm & B_INL_AUTO_CAL ) != 0 )

   U_INT16 fi_channel;
   U_INT16 bi_channel;

    LockResource( &Inst_Status.Pneu.Resource_Lock );

#if 0

    /* The below cases SHOULD work but don't ; they need investigation */
    if (
         ( GetInletType(GetFrontInletPtr() )== VOLATILES  &&
           GetInletInjectMode(GetFrontInletPtr() )== SPLITLESS  && !Inst_Status.Pneu.Frnt_Inlet.Inlet_Purge  ) ||
         ( Inst_Status.Pneu.Frnt_Inlet.VI_Flow_Mode )
       )  parm = parm & ~F_INL_AUTO_CAL ;

    if (
         ( GetInletType(GetBackInletPtr() )== VOLATILES  &&
           GetInletInjectMode(GetBackInletPtr() )== SPLITLESS  && !Inst_Status.Pneu.Back_Inlet.Inlet_Purge  ) ||
         ( Inst_Status.Pneu.Back_Inlet.VI_Flow_Mode )
       )  parm = parm & ~B_INL_AUTO_CAL ;

#endif


    if ( (do_fi) &&
         ( Inst_Status.Pneu.Frnt_Inlet.PCB_Inlet_Control_Mode == FWD_PRES_NO_FLOW )
         #if 0  /* below nuked code tryed to derive PCB2 control mode; just "ask" it instead as above */
         (
           ( (( Inst_Config.Pneu.Frnt_Inlet.Type == VOLATILES )
                                     && ( GetInletInjectMode(GetFrontInletPtr() )  == DIRECT)) ||
             ( Inst_Config.Pneu.Frnt_Inlet.Type == PP  ) || ( Inst_Config.Pneu.Frnt_Inlet.Type == ACI ) ||
             ( Inst_Config.Pneu.Frnt_Inlet.Type == SIMDIST )
           )
           &&
           (Inst_Status.Pneu.Frnt_Inlet.Has_Column )
         )
         #endif
       )
    {
         fi_channel = FRNT_INLET_PRESSURE_CHANNEL; /* REVISIT !!! Ask Rick: why here even if do_fi=0 ?? */
    }
    else
    {
         fi_channel = FRNT_INLET_FLOW_CHANNEL;
    }

    if ( (do_bi) &&
         ( Inst_Status.Pneu.Back_Inlet.PCB_Inlet_Control_Mode == FWD_PRES_NO_FLOW )
         #if 0  /* below nuked code tryed to derive PCB2 control mode; just "ask" it instead as above */
         (
           ( (( Inst_Config.Pneu.Back_Inlet.Type == VOLATILES )
                                     && ( GetInletInjectMode(GetFrontInletPtr() )  == DIRECT)) ||
             ( Inst_Config.Pneu.Back_Inlet.Type == PP  ) || ( Inst_Config.Pneu.Back_Inlet.Type == ACI ) ||
             ( Inst_Config.Pneu.Back_Inlet.Type == SIMDIST )
           )
           &&
           (Inst_Status.Pneu.Back_Inlet.Has_Column )
         )
         #endif
       )

    {
         bi_channel = BACK_INLET_PRESSURE_CHANNEL;
    }
    else
    {
         bi_channel = BACK_INLET_FLOW_CHANNEL;
    }

    ReleaseResource( &Inst_Status.Pneu.Resource_Lock );

    /* turn off inlet source flows */

    if ( do_fi )  WriteDutyCycle( fi_channel, 0 );
    if ( do_bi )  WriteDutyCycle( bi_channel, 0 );

    /* wait for inlet flows to drop to zero */


    Inst_Status.Pneu.Auto_Cal_Timer = AUTO_CAL_DELAY;
    while (( Inst_Status.Pneu.Auto_Cal_Timer > 0 ) && ( Inst_Status.Pneu.Auto_Cal_Timer <= AUTO_CAL_DELAY )) Task_yield();

    /* read the new offsets */

    if ( do_fi ) Inst_Status.Pneu.Frnt_Inlet.Last_Auto_Cal_Offset =  ReadInletCalFlowOffset ( &Inst_Status.Pneu.Frnt_Inlet );
    if ( do_bi ) Inst_Status.Pneu.Back_Inlet.Last_Auto_Cal_Offset =  ReadInletCalFlowOffset ( &Inst_Status.Pneu.Back_Inlet );

    /* restore the inlet source flows */

    if ( do_fi ) EndFixedDutyCycle ( fi_channel );
    if ( do_bi ) EndFixedDutyCycle ( bi_channel );

    /* save the new calibration values */


    if ( do_fi )
    {
        if (SaveFsCalOffset ( &Inst_Status.Pneu.Frnt_Inlet,
                               Inst_Status.Pneu.Frnt_Inlet.Last_Auto_Cal_Offset,
                               TRUE) != OK )
        {
            SetException( FI_FS_AUTO_CAL_FAILED );
        }
    }

    if ( do_bi )
    {
        if (SaveFsCalOffset ( &Inst_Status.Pneu.Back_Inlet,
                               Inst_Status.Pneu.Back_Inlet.Last_Auto_Cal_Offset,
                               TRUE) != OK )
        {
            SetException( BI_FS_AUTO_CAL_FAILED );
        }
    }

    Inst_Status.Pneu.Frnt_Inlet.Ready.FS_Auto_Zero = FALSE;
    Inst_Status.Pneu.Back_Inlet.Ready.FS_Auto_Zero = FALSE;
}


/**begin_proto**/

void ZeroFlowSensor( pINLET_STATUS status, U_INT32 data_comm )

/**end_proto**/
{
   INT16 correction;
   U_INT16 channel;
   UI_ERR   error;


    LockResource( &Inst_Status.Pneu.Resource_Lock );

    if ( status->Wkfile->On_Off == OFF )
    {
         if ( data_comm )
         {
              /* just save the error for the compleator to pick up */
              status->Flow_Sensor_Zero_State = (U_INT32)INVALID_OP;
         }
         else
         {
              /* pop up a warning message on the display */
              DisplayErrors ( (status->Position == FRNT_INLET) ? MSG_FI_NOT_ON_ERR : MSG_BI_NOT_ON_ERR );
         }

         ReleaseResource( &Inst_Status.Pneu.Resource_Lock );
    };

    #if 0
    if ((( status->Config->Type == PP ) || ( status->Config->Type == ACI )
                                        || ( status->Config->Type == SIMDIST )) && ( status->Has_Column ))
    #endif
    if ( status->PCB_Inlet_Control_Mode == FWD_PRES_NO_FLOW )
    {
         channel = (status->Position == FRNT_INLET ) ?
                         FRNT_INLET_PRESSURE_CHANNEL :
                         BACK_INLET_PRESSURE_CHANNEL ;
    }
    else
    {
         channel = (status->Position == FRNT_INLET ) ?
                             FRNT_INLET_FLOW_CHANNEL :
                             BACK_INLET_FLOW_CHANNEL ;
    }

    ReleaseResource( &Inst_Status.Pneu.Resource_Lock );

    /* turn off inlet source flows */

    WriteDutyCycle( channel, 0 );

    /* wait for inlet flows to drop to zero */

    Inst_Status.Pneu.Auto_Cal_Timer = AUTO_CAL_DELAY;
    while (( Inst_Status.Pneu.Auto_Cal_Timer > 0 ) && ( Inst_Status.Pneu.Auto_Cal_Timer <= AUTO_CAL_DELAY )) Task_yield();

    /* read the new offset */
    correction =  ReadInletCalFlowOffset ( status );

    /* restore the inlet source flows */

    EndFixedDutyCycle ( channel );

    /* save the new calibration value */
    error = SaveFsCalOffset ( status, correction, FALSE);

    if (( data_comm ) || (error != OK ))
    {
         if ( data_comm )
         {
              /* just save the error for the compleator to pick up */
              status->Flow_Sensor_Zero_State = (U_INT32)error;
         }
         else
         {
              /* pop up a warning message on the display */
              DisplayErrors ( (status->Position == FRNT_INLET) ? MSG_FI_CAL_RANGE_ERR : MSG_BI_CAL_RANGE_ERR );
         }
    }

}

/***********************************************************************/
/* FUNCTION:                                                           */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:                                                            */
/*                                                                     */
/* RETURNED VALUE:                                                     */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/***********************************************************************/

void ReadEepromThermalInfo ( U_INT16 module_number, U_INT16 *thermal_info )
{
     U_INT16 i;

     for ( i= THERMAL_ADDR; i < THERMAL_ADDR + THERMAL_SIZE ; i++ )
     {
          (void)ReadEeprom( module_number, i , thermal_info );
          thermal_info++;
     }
}

void SaveEepromThermalInfo ( U_INT16 module_number, U_INT16 *thermal_info )
{
     U_INT16 i;

     for ( i= THERMAL_ADDR ; i < THERMAL_ADDR + THERMAL_SIZE ; i++ )
     {
          (void)WriteEeprom( module_number, i , *thermal_info );
          thermal_info++;
     }
}


/***********************************************************************/
/* FUNCTION:                                                           */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:                                                            */
/*                                                                     */
/* RETURNED VALUE:                                                     */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/***********************************************************************/
/**begin_proto**/

U_INT8 CountInletChangeRequests ( pINLET_STATUS status )

/**end_proto**/
{
    return Pending_Cmds[ (status->Position == FRNT_INLET) ? FRNT_INLET_GAS : BACK_INLET_GAS ];
}


/**begin_proto**/

U_INT8 CountDetChangeRequests ( pDETECTOR_STATUS status, U_INT8 gas_num )

/**end_proto**/
{

   if ( status->Position == FRNT_DET )
   {
       switch ( gas_num )
       {
            case 1:  return Pending_Cmds [ FDET_FUEL_GAS ];
            case 2:  return Pending_Cmds [ FDET_UTIL_GAS ];
            case 3:  return Pending_Cmds [ FDET_MUG_GAS  ];
       }
   }
   else
   {
       switch ( gas_num )
       {
            case 1:  return Pending_Cmds [ BDET_FUEL_GAS ];
            case 2:  return Pending_Cmds [ BDET_UTIL_GAS ];
            case 3:  return Pending_Cmds [ BDET_MUG_GAS  ];
       }
   }
   return 0;
}

/**begin_proto**/

U_INT8 CountAuxChangeRequests ( pAUX_STATUS status )

/**end_proto**/
{

    switch (status->Position )
    {
       case AUX_3: return Pending_Cmds[ AUX_3_GAS ];
       case AUX_4: return Pending_Cmds[ AUX_4_GAS ];
       case AUX_5: return Pending_Cmds[ AUX_5_GAS ];
    }

    return 0;
}
/***********************************************************************/
/* FUNCTION:                                                           */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:                                                            */
/*                                                                     */
/* RETURNED VALUE:                                                     */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/***********************************************************************/
/**begin_proto**/

void SendInletGasChangeRequest( pINLET_STATUS status, GAS_TYPE gas )

/**end_proto**/
{

   LockResource( &Task_Cmd_Resource );

   INTERRUPTS_OFF

   if ( status->Config->Gas_Type == gas )
   {
        /* already set to this value */
        INTERRUPTS_ON
        ReleaseResource( &Task_Cmd_Resource );
        return;
   }


   status->Config->Gas_Type = gas;

   if ( EpcInlet( status ) )
   {
        SendGasTaskCmd( (status->Position == FRNT_INLET ) ? FRNT_INLET_GAS : BACK_INLET_GAS, (U_INT32)gas  );
   }

   INTERRUPTS_ON

   ReleaseResource( &Task_Cmd_Resource );
}


static const Det_Gas_Cmds[ ][3] = {{ FDET_FUEL_GAS,
                                     FDET_UTIL_GAS,
                                     FDET_MUG_GAS },
                                   { BDET_FUEL_GAS,
                                     BDET_UTIL_GAS,
                                     BDET_MUG_GAS } };
/**begin_proto**/

void   SendDetGasChangeRequest( pDETECTOR_STATUS status, U_INT8 gas_num, GAS_TYPE gas )

/**end_proto**/
{

   GAS_TYPE *p_gas;

   switch ( gas_num )
   {
       case 1: p_gas = &status->Config->Gas_1.Gas_Type;
               break;
       case 2: p_gas = &status->Config->Gas_2.Gas_Type;
               break;
       default:
       case 3: p_gas = &status->Config->Gas_3.Gas_Type;
               break;
   }

   LockResource( &Task_Cmd_Resource );

   INTERRUPTS_OFF

   if ( *p_gas == gas )
   {
        /* already set to this value */
        INTERRUPTS_ON
        ReleaseResource( &Task_Cmd_Resource );
        return;
   }

   *p_gas = gas;

   if ( EpcDetector( status ) )
   {
       SendGasTaskCmd( Det_Gas_Cmds[ ( status->Position == FRNT_DET ) ? 0 : 1 ][ gas_num -1 ], (U_INT32)gas );
   }

   INTERRUPTS_ON

   ReleaseResource( & Task_Cmd_Resource );

}


/**begin_proto**/

void SendAuxGasChangeRequest( pAUX_STATUS status, GAS_TYPE gas )

/**end_proto**/
{
   LockResource( &Task_Cmd_Resource );

   INTERRUPTS_OFF

   if ( status->Config->Gas_Type == gas )
   {
        /* already set to this value */
        INTERRUPTS_ON
        ReleaseResource( &Task_Cmd_Resource );
        return;
   }

   status->Config->Gas_Type = gas;

   switch ( status->Position )
   {
      case AUX_3: SendGasTaskCmd( AUX_3_GAS, (U_INT32)gas  );
                  break;
      case AUX_4: SendGasTaskCmd( AUX_4_GAS, (U_INT32)gas  );
                  break;
      case AUX_5: SendGasTaskCmd( AUX_5_GAS, (U_INT32)gas  );
                  break;
   }

   INTERRUPTS_ON

   ReleaseResource( & Task_Cmd_Resource );
}

/***********************************************************************/
/* FUNCTION:                                                           */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:                                                            */
/*                                                                     */
/* RETURNED VALUE:                                                     */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/***********************************************************************/
/**begin_proto**/

void SendInletCalibRequest( pINLET_STATUS status )

/**end_proto**/
{
   LockResource( &Task_Cmd_Resource );

   SendGasTaskCmd( (status->Position == FRNT_INLET ) ? FRNT_INLET_CALIB : BACK_INLET_CALIB, CALIB  );

   ReleaseResource( & Task_Cmd_Resource );
}

/**begin_proto**/

void SendDetCalibRequest( pDETECTOR_STATUS status )

/**end_proto**/
{
   LockResource( &Task_Cmd_Resource );

   SendGasTaskCmd( (status->Position == FRNT_DET ) ? FRNT_DET_CALIB : BACK_DET_CALIB, CALIB  );

   ReleaseResource( & Task_Cmd_Resource );
}

/**begin_proto**/

void SendPneuAuxCalibRequest( )

/**end_proto**/
{
   LockResource( &Task_Cmd_Resource );

   SendGasTaskCmd( PNEU_AUX_CALIB, CALIB );

   ReleaseResource( & Task_Cmd_Resource );
}

/**begin_proto**/

void SendInletDisableUserRequest( pINLET_STATUS status )

/**end_proto**/
{
   LockResource( &Task_Cmd_Resource );

   SendGasTaskCmd( (status->Position == FRNT_INLET ) ? FRNT_INLET_CALIB : BACK_INLET_CALIB, DISABLE_USER  );

   ReleaseResource( & Task_Cmd_Resource );
}

/**begin_proto**/

void SendDetDisableUserRequest( pDETECTOR_STATUS status )

/**end_proto**/
{
   LockResource( &Task_Cmd_Resource );

   SendGasTaskCmd( (status->Position == FRNT_DET ) ? FRNT_DET_CALIB : BACK_DET_CALIB, DISABLE_USER  );

   ReleaseResource( & Task_Cmd_Resource );
}

/**begin_proto**/

void SendPneuAuxDisableUserRequest(  )

/**end_proto**/
{
   LockResource( &Task_Cmd_Resource );

   SendGasTaskCmd( PNEU_AUX_CALIB, DISABLE_USER );

   ReleaseResource( & Task_Cmd_Resource );
}


/**begin_proto**/

void SendInletEnableUserRequest( pINLET_STATUS status )

/**end_proto**/
{
   LockResource( &Task_Cmd_Resource );

   SendGasTaskCmd( (status->Position == FRNT_INLET ) ? FRNT_INLET_CALIB : BACK_INLET_CALIB, ENABLE_USER  );

   ReleaseResource( & Task_Cmd_Resource );
}

/**begin_proto**/

void SendDetEnableUserRequest( pDETECTOR_STATUS status )

/**end_proto**/
{
   LockResource( &Task_Cmd_Resource );

   SendGasTaskCmd( (status->Position == FRNT_DET ) ? FRNT_DET_CALIB : BACK_DET_CALIB, ENABLE_USER  );

   ReleaseResource( & Task_Cmd_Resource );
}

/**begin_proto**/

void SendPneuAuxEnableUserRequest(  )

/**end_proto**/
{
   LockResource( &Task_Cmd_Resource );

   SendGasTaskCmd( PNEU_AUX_CALIB, ENABLE_USER );

   ReleaseResource( & Task_Cmd_Resource );
}


/**begin_proto**/

void SendInletScratchRequest( pINLET_STATUS status )

/**end_proto**/
{
   LockResource( &Task_Cmd_Resource );

   SendGasTaskCmd( (status->Position == FRNT_INLET ) ? FRNT_INLET_CALIB : BACK_INLET_CALIB, SCRATCH  );

   ReleaseResource( & Task_Cmd_Resource );
}

/**begin_proto**/

void SendDetScratchRequest( pDETECTOR_STATUS status )

/**end_proto**/
{
   LockResource( &Task_Cmd_Resource );

   SendGasTaskCmd( (status->Position == FRNT_DET ) ? FRNT_DET_CALIB : BACK_DET_CALIB, SCRATCH  );

   ReleaseResource( & Task_Cmd_Resource );
}

/**begin_proto**/

void SendPneuAuxScratchRequest(  )

/**end_proto**/
{
   LockResource( &Task_Cmd_Resource );

   SendGasTaskCmd( PNEU_AUX_CALIB, SCRATCH );

   ReleaseResource( & Task_Cmd_Resource );
}

/**begin_proto**/

void SendSensorNoiseRequest()

/**end_proto**/
{
   INTERRUPTS_OFF

   SendGasTaskCmd( CALC_SENSOR_NOISE, 0 );

   INTERRUPTS_ON
}

/**begin_proto**/

void SendExecTestCmdRequest( )

/**end_proto**/
{
   LockResource( &Task_Cmd_Resource );

   SendGasTaskCmd( EXEC_TEST_CMD,  0             );

   ReleaseResource( & Task_Cmd_Resource );
}

/***********************************************************************/
/* FUNCTION:                                                           */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:                                                            */
/*                                                                     */
/* RETURNED VALUE:                                                     */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/***********************************************************************/



static void DoInletGas( U_INT32 parm, void *status, U_INT8 number )
{
    CALIB_STRUCT calib;

    RebuildInletCompTables ( status );

    if ( InletUserCalibState( status ) != USER_ENABLED )
    {
        (void) ReadAutoCalOffset( status, &calib );
        ((pINLET_STATUS)status)->Calib.F_Sensor_Offset = calib.Pos_2.Offset;
    }

    (void)parm;
    (void)number;

}


static void DoDetGas( U_INT32 parm, void *status, U_INT8 number )
{
    ReBuildDetGasCompTable ( status, number );

    (void)parm;

}

static void DoAuxGas( U_INT32 parm, void *status, U_INT8 number )
{
    DownloadAuxPids( status );

    (void)parm;
    (void)number;

}

static void DoInletCalib ( U_INT32 parm, void *status, U_INT8 number )
{
    switch ( parm )
    {
    case CALIB:          SaveInletCalib ( status );
                         break;

    case FACTORY_CALIB:  SaveInletFactoryCalib ( status );
                         break;

    case ENABLE_USER:    (void)ChangeInletCalibState( status, ON );
                         break;

    case DISABLE_USER:   (void)ChangeInletCalibState( status, OFF );
                         break;

    case SCRATCH:        ScratchInletCalib ( status );
                         break;
    }

    /* pcb pid's are dependant on sensor offsets */
    /* if user calib changes the offset, new pids*/
    /* must be sent to the pcb                   */
    DownloadInletPids ( status );

    (void)number;
}


static void DoDetCalib( U_INT32 parm, void *status, U_INT8 number )
{
    switch ( parm )
    {
    case CALIB:          SaveDetCalib ( status );
                         break;

    case FACTORY_CALIB:  SaveDetFactoryCalib ( status );
                         break;

    case ENABLE_USER:    (void)ChangeDetCalibState( status, ON );
                         break;

    case DISABLE_USER:   (void)ChangeDetCalibState( status, OFF );
                         break;

    case SCRATCH:        ScratchDetCalib ( status );
                         break;
    }

    (void)number;

}


static void DoPneuAuxCalib( U_INT32 parm, void *status, U_INT8 number )
{
    switch ( parm )
    {
    case CALIB:          SaveAuxCalib ( status );
                         break;

    case FACTORY_CALIB:  SaveAuxFactoryCalib ( status );
                         break;

    case ENABLE_USER:    (void)ChangeAuxCalibState( ON );
                         break;

    case DISABLE_USER:   (void)ChangeAuxCalibState( OFF );
                         break;

    case SCRATCH:        ScratchAuxCalib ( status );
                         break;
    }

    (void)number;

}

static void DoCalcSensorNoise( U_INT32 parm, void *status, U_INT8 number )
{
    MonitorSensorNoise();

    (void)parm;
    (void)status;
    (void)number;

}


static void DoFsAutoZero( U_INT32 parm, void *status, U_INT8 number )
{
    AutoZeroFlowSensors( parm );

    (void)parm;
    (void)number;
    (void)status;
}

static void DoFsUserZero( U_INT32 parm, void *status, U_INT8 number )
{
    ZeroFlowSensor( status, parm );

    (void)number;
}

static void ExecTestCmd      ( U_INT32 parm, void *status, U_INT8 number )
{

#ifdef INCLUDE_PNEU_TEST

    ExecTestCmdEntry ();

#endif

    (void)parm;
    (void)number;
    (void)status;
}


static void SaveInletPids( U_INT32 parm, void *status, U_INT8 number )
{

   SaveEepromThermalInfo ( ((pINLET_STATUS)status)->Module_Number, (U_INT16 *)parm );

   (void)number;
}

static void ReadInletPids( U_INT32 parm, void *status, U_INT8 number )
{

   ReadEepromThermalInfo ( ((pINLET_STATUS)status)->Module_Number, (U_INT16 *) parm );

   (void)number;
}


static void SaveDetPids( U_INT32 parm, void *status, U_INT8 number )
{

   SaveEepromThermalInfo ( ((pDETECTOR_STATUS)status)->Module_Number, (U_INT16 *) parm );

   (void)number;
}

static void ReadDetPids( U_INT32 parm, void *status, U_INT8 number )
{

   ReadEepromThermalInfo ( ((pDETECTOR_STATUS)status)->Module_Number, (U_INT16 *) parm );

   (void)number;
}



/***********************************************************************/
/* FUNCTION:                                                           */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:                                                            */
/*                                                                     */
/* RETURNED VALUE:                                                     */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/***********************************************************************/
/**begin_proto**/

void SendGasTaskCmd( U_INT8 cmd, U_INT32 parm )

/**end_proto**/
{
      pGAS_TASK_MSG buffer;

      INTERRUPTS_OFF

      /* walk queues looking for an existing buffer with this cmd */
      /* if it is on the queue, it has not been executed yet, and */
      /* there is no reason to queue a duplicate command.         */


      if ( Gas_Task_Cmd_Table[ cmd ].allow_duplicates == FALSE )
      {
          /* find an exiting entry with the same cmd */

          buffer = (pGAS_TASK_MSG)Gas_Task_Cmds.Queue.Next_Entry;

          while ( buffer != (pGAS_TASK_MSG)&Gas_Task_Cmds )
          {
              if ( buffer->Cmd == cmd )
              {
                   buffer->Parm = parm;  /* replace the parm with the current one */

                   INTERRUPTS_ON         /* reenable interrupts and get out, we are done */
                   return;
              }
              buffer = (pGAS_TASK_MSG)buffer->Queue.Next_Entry;
          }
      }

      /* did not find any, so add one!  */

      GetBuffer(buffer, &Gas_Task_Free_Buffers );

      if ( buffer == 0 )        /* no buffers available, just ignore the command request */
      {
          INTERRUPTS_ON         /* reenable interrupts and get out, we are done */
          return;
      }

      buffer->Cmd   = cmd;
      buffer->Parm  = parm;

      LinkBufferToTail( buffer, &Gas_Task_Cmds );

      Pending_Cmds[ cmd ] ++;

      INTERRUPTS_ON

}

/***********************************************************************/
/* FUNCTION:                                                           */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:                                                            */
/*                                                                     */
/* RETURNED VALUE:                                                     */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/***********************************************************************/
/**begin_proto**/

void ProcessGasTaskCmd ( pGAS_TASK_MSG buffer )

/**end_proto**/
{

     (Gas_Task_Cmd_Table[ buffer->Cmd ].executor)( buffer->Parm,
                                                   Gas_Task_Cmd_Table[ buffer->Cmd ].status_ptr,
                                                   Gas_Task_Cmd_Table[ buffer->Cmd ].number      );

    INTERRUPTS_OFF

    Pending_Cmds[ buffer->Cmd ] --;

    INTERRUPTS_ON

}


/***********************************************************************/
/* FUNCTION:                                                           */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:                                                            */
/*                                                                     */
/* RETURNED VALUE: none                                                */
/*                                                                     */
/*                                                                     */
/*  This is a background task used to do calculations for the tables   */
/*  used in foreground.  It may take many seconds (>30) to process     */
/*  all the calculations used by a method load.  Clearly, this is      */
/*  a time window when a user could load a second method, or undo the  */
/*  first load.  This, unfortunately, gives us the chance of stacking  */
/*  many requests for table calculations.  To avoid some of this delay */
/*  we will have this task scan the cmd queues looking for duplicate   */
/*  requests and deleting them.                                        */
/*                                                                     */
/***********************************************************************/

void GasPassTask(void)
{


   pGAS_TASK_MSG buffer;

   InitResource( &Task_Cmd_Resource );


   while (TRUE)
   {
      if ( DoingMethodInstall() )  /* hold off gas task when loading a method */
      {
           Task_yield ();
           continue;
      }

      LockResource( &Task_Cmd_Resource );

      INTERRUPTS_OFF

      GetBuffer(buffer, &Gas_Task_Cmds);

      if ( buffer == 0 )
      {
          INTERRUPTS_ON
          ReleaseResource( &Task_Cmd_Resource );

          Task_yield ();            /* Yield cpu to other background tasks */
          continue;
      }

      INTERRUPTS_ON
      ReleaseResource( &Task_Cmd_Resource );

      ProcessGasTaskCmd( buffer );

      LinkBufferToTail( buffer, &Gas_Task_Free_Buffers );

   }
}
